var xmlData = null;
var fileContent = null;
var msgSourceWindow = null;
var modelId = null;

//Fix for IE (IE do not support 'startsWith') 
if (!String.prototype.startsWith) 
{
  String.prototype.startsWith = function(searchString, position)
  {
    position = position || 0;
    return this.substr(position, searchString.length) === searchString;
  };
}

function loadModelSelect() {
    $('#model_generalRes_select').empty();
    var modelIdList = xmlData.find('SimulationResults > PathAnalysis');
    for (var i = 0; i < modelIdList.length; i++) {
        $('#model_generalRes_select').append($('<option>', {
            value : modelIdList[i].getAttribute('modelId'),
            text : modelIdList[i].getAttribute('modelName')
        }));
        if(i==0){
            $('#model_generalRes_select').val(modelIdList[i].getAttribute('modelId'));
            modelId = modelIdList[i].getAttribute('modelId');
        }
    }
}

function onModelSelectChange() {
    modelId = $('#model_generalRes_select').find(":selected").val();
    
    loadCharts();
}



function loadActivitiesSelect() {
    $('#activityRes_select').empty();
    var objectList = xmlData.find('SimulationResults > PathAnalysis[modelId="'+modelId+'"] > ObjectMeasures > Object ');
    for (var i = 0; i < objectList.length; i++) {
        $('#activityRes_select').append($('<option>', {
            value : objectList[i].getAttribute('id'),
            text : objectList[i].getAttribute('name')
        }));
        if(i==0){
            $('#activityRes_select').val(objectList[i].getAttribute('id'));
        }
    }
    onActivitiesSelectChange();
}

function onActivitiesSelectChange() {
    var objectId = $('#activityRes_select').find(":selected").val();
    
    var object = xmlData.find('SimulationResults > PathAnalysis[modelId="'+modelId+'"] > ObjectMeasures > Object[id="'+objectId+'"]')[0];
    $("#numExec_activityRes_lbl").text(object.getAttribute('numberOfExecutions'));
    $("#costs_activityRes_lbl").text(object.getAttribute('costs'));
    $("#totCosts_activityRes_lbl").text(object.getAttribute('totCosts'));
    $("#execTime_activityRes_lbl").text(object.getAttribute('executionTime'));
    $("#totExecTime_activityRes_lbl").text(object.getAttribute('totExecutionTime'));
}

function loadDeadlockPathSelect() {
    $('#totDeadP_generalRes_select').empty();
    var pathList = xmlData.find('SimulationResults > PathAnalysis[modelId="'+modelId+'"] > Paths > Path[deadlocked="true"]');
    for (var i = 0; i < pathList.length; i++) {

        $('#totDeadP_generalRes_select').append($('<option>', {
            value : pathList[i].getAttribute('id'),
            text : pathList[i].getAttribute('id')
        }));
    }
}
function showActivity() {
    var objectId = $('#activityRes_select').find(":selected").val();
    var jsonActivityInfo = generateJsonActivity(objectId);
    if(msgSourceWindow == null) {
        alert("Activity:\n"+JSON.stringify(jsonActivityInfo, null, 2));
    } else {
        msgSourceWindow.postMessage(jsonActivityInfo, "*");
    }
}
function generateJsonActivity(objectId) {
    return {
        command: "show_activity",
        modelId: modelId,
        objList: [[objectId]]
    };
}


function loadGeneralResults() {
    var generalMeasuresNode = xmlData.find('SimulationResults > PathAnalysis[modelId="'+modelId+'"] > GeneralMeasures');

    $("#avgCost_generalRes_lbl").text(generalMeasuresNode.find('AverageCosts').text());
    $("#maxCost_generalRes_lbl").text(generalMeasuresNode.find('MaxCosts').text());
    $("#maxCostTrace_generalRes_lbl").text('Trace: ' + generalMeasuresNode.find('MaxCosts')[0].getAttribute("traceId"));
    $("#minCost_generalRes_lbl").text(generalMeasuresNode.find('MinCosts').text());
    $("#minCostTrace_generalRes_lbl").text('Trace: ' + generalMeasuresNode.find('MinCosts')[0].getAttribute("traceId"));
    $("#totCost_generalRes_lbl").text(generalMeasuresNode.find('TotalCosts').text());
    $("#dailyExec_generalRes_lbl").text(generalMeasuresNode.find('AverageExecutionsInOneDay').text());
    $("#avgExecTime_generalRes_lbl").text(generalMeasuresNode.find('AverageExecutionTime').text());
    $("#maxExecTime_generalRes_lbl").text(generalMeasuresNode.find('MaxExecutionTime').text());
    $("#maxExecTimeTrace_generalRes_lbl").text('Trace: ' + generalMeasuresNode.find('MaxExecutionTime')[0].getAttribute("traceId"));
    $("#minExecTime_generalRes_lbl").text(generalMeasuresNode.find('MinExecutionTime').text());
    $("#minExecTimeTrace_generalRes_lbl").text('Trace: ' + generalMeasuresNode.find('MinExecutionTime')[0].getAttribute("traceId"));
    $("#totExecTime_generalRes_lbl").text(generalMeasuresNode.find('TotalExecutionTime').text());
    $("#maxWaitTime_generalRes_lbl").text(generalMeasuresNode.find('MaxWaitingTime').text());
    $("#maxWaitTimeTrace_generalRes_lbl").text('Trace: ' + generalMeasuresNode.find('MaxWaitingTime')[0].getAttribute("traceId"));
    $("#maxMsgWaitTime_generalRes_lbl").text(generalMeasuresNode.find('MaxMessageWaitingTime').text());
    $("#maxMsgWaitTimeTrace_generalRes_lbl").text('Trace: ' + generalMeasuresNode.find('MaxMessageWaitingTime')[0].getAttribute("traceId"));
    $("#minWaitTime_generalRes_lbl").text(generalMeasuresNode.find('MinWaitingTime').text());
    $("#minWaitTimeTrace_generalRes_lbl").text('Trace: ' + generalMeasuresNode.find('MinWaitingTime')[0].getAttribute("traceId"));
    $("#minMsgWaitTime_generalRes_lbl").text(generalMeasuresNode.find('MinMessageWaitingTime').text());
    $("#minMsgWaitTimeTrace_generalRes_lbl").text('Trace: ' + generalMeasuresNode.find('MinMessageWaitingTime')[0].getAttribute("traceId"));
    $("#totDeadT_generalRes_lbl").text(generalMeasuresNode.find('TotalDeadlockedTraces').text());
    $("#totDeadP_generalRes_lbl").text(generalMeasuresNode.find('TotalDeadlockedPaths').text());
    $("#totTerm_generalRes_lbl").text(generalMeasuresNode.find('TotalEndTerminateEvents').text());
    $("#totRuns_generalRes_lbl").text(generalMeasuresNode.find('TotalRuns').text());
    $("#totTraces_generalRes_lbl").text(generalMeasuresNode.find('TotalTraces').text());
    $("#totPaths_generalRes_lbl").text(generalMeasuresNode.find('TotalPaths').text());

    loadDeadlockPathSelect();
}

function onDeadPathSelectChange() {
    var pathName = $('#totDeadP_generalRes_select').find(":selected").text();
    loadPathInfos(pathName);
    $('#pathListSelect').val(pathName);
}

function changeTrace(evt) {
    var traceId = $(evt.target).text()
    if (traceId.indexOf(":") != -1)
        traceId = traceId.substring(7);
    if (traceId == "")
        return;
    $('#traceListSelect').val(traceId);
    onTraceSelectChange();
}

function changePath(evt) {
    var pathId = $(evt.target).text();
    if (pathId == "")
        return;
    $('#pathListSelect').val(pathId);
    onPathSelectChange();
}







var lastPathProbabilitiesLabel = null;
function onOverPathProbabilities(evt) {
    var activePoints = chartPathProbabilities.getSegmentsAtEvent(evt);
    if (activePoints.length == 0)
        return;

    var pathName = activePoints[0].label;

    if (lastPathProbabilitiesLabel != null && pathName == lastPathProbabilitiesLabel)
        return;
    lastPathProbabilitiesLabel = pathName;

    // the following code is executed only on selection change
    $('#pathListSelect').val(pathName);
    loadPathInfos(pathName);
};

function onPathSelectChange() {
    var pathName = $('#pathListSelect').find(":selected").text();
    loadPathInfos(pathName);
}

function loadPathInfos(pathId) {
    var pathNode = xmlData.find('SimulationResults > PathAnalysis[modelId="'+modelId+'"] > Paths > Path[id="' + pathId + '"]');
    if (pathNode.length != 1) {
        alert("Error retriving the Path with id: " + pathId);
        return;
    }
    pathNode = pathNode[0];

    $("#name_pathProb_lbl").text(pathId);
    $("#prob_pathProb_lbl").text(pathNode.getAttribute("pathProbability") + '%');
    $("#numTraces_pathProb_lbl").text(pathNode.getAttribute("numberOfTraces"));
    $("#isDead_pathProb_lbl").text(pathNode.getAttribute("deadlocked"));
    $("#isTermin_pathProb_lbl").text(pathNode.getAttribute("terminateEvent"));

    $("#minwt_pathProb_lbl").text(pathNode.getAttribute("minWaitingTime"));
    $("#minsdwt_pathProb_lbl").text(pathNode.getAttribute("minWaitingTimeSD"));
    $("#minwtt_pathProb_lbl").text(pathNode.getAttribute("minWaitingTimeTraceId"));
    $("#minmsgwt_pathProb_lbl").text(pathNode.getAttribute("minMsgWaitingTime"));
    $("#minmsgsdwt_pathProb_lbl").text(pathNode.getAttribute("minMsgWaitingTimeSD"));
    $("#minmsgwtt_pathProb_lbl").text(pathNode.getAttribute("minMsgWaitingTimeTraceId"));
}

var chartPathProbabilities = null;
function generatePathProbabilitiesPie() {

    if (chartPathProbabilities != null)
        chartPathProbabilities.destroy();

    $('#pathListSelect').empty();

    var chartPathProbabilitiesData = [];
    var chartPathProbabilitiesUsedColorList = [];
    var pathList = xmlData.find('SimulationResults > PathAnalysis[modelId="'+modelId+'"] > Paths > Path');

    for (var i = 0; i < pathList.length; i++) {
        var color = randomColorNotIn(chartPathProbabilitiesUsedColorList);
        chartPathProbabilitiesUsedColorList.push(color);
        // var color = getPathColorMap(pathList.length)[i];

        chartPathProbabilitiesData.push({
            value : pathList[i].getAttribute('pathProbability'),
            label : pathList[i].getAttribute('id'),
            color : color,
            highlight : '#E2E2E2'
        });

        $('#pathListSelect').append($('<option>', {
            value : pathList[i].getAttribute('id'),
            text : pathList[i].getAttribute('id')
        }));
    }

    chartPathProbabilities = new Chart($("#canvasPathProbabilities").get(0).getContext("2d")).Doughnut(chartPathProbabilitiesData, {});

    onPathSelectChange();
}

function showPath() {
    var pathName = $('#pathListSelect').find(":selected").val();
    var jsonPathInfo = generateJsonPath(pathName);
    if(msgSourceWindow == null) {
        alert("Path Elements:\n"+JSON.stringify(jsonPathInfo, null, 2));
    } else {
        msgSourceWindow.postMessage(jsonPathInfo, "*");
    }
}
function generateJsonPath(pathId) {
    var tmpObjList = [];
    var xmlObjList = xmlData.find('SimulationResults > PathAnalysis[modelId="'+modelId+'"] > Paths > Path[id="' + pathId + '"] > Set > Object').each(function(){
        var objId = $(this).text();
        var step = $(this).attr('step');
        tmpObjList.push([objId, step]);
    });
    
    var objList = [];
    var finished = false;
    var counter = 1;
    do{
        var parallelObjList = [];
        for(var i=0;i<tmpObjList.length;i++)
            if(tmpObjList[i][1] == counter)
                parallelObjList.push(tmpObjList[i][0]);
        counter++;
        if(parallelObjList.length == 0)
            finished = true;
        else
            objList.push(parallelObjList);
    }while(!finished);
    
    return {
        command: "show_path",
        modelId: modelId,
        objList: objList
    };
}









var lastTraceProbabilitiesLabel = null;
function onOverTraceProbabilities(evt) {
    var activePoints = chartTraceProbabilities.getSegmentsAtEvent(evt);
    if (activePoints.length == 0)
        return;

    var traceName = activePoints[0].label;

    if (lastTraceProbabilitiesLabel != null && traceName == lastTraceProbabilitiesLabel)
        return;
    lastTraceProbabilitiesLabel = traceName;

    // the following code is executed only on selection change
    $('#traceListSelect').val(traceName);
    loadTraceInfos(traceName);
};

function onTraceSelectChange() {
    var traceName = $('#traceListSelect').find(":selected").text();
    loadTraceInfos(traceName);
}

function loadTraceInfos(traceId) {
    var traceNodeList = xmlData.find('SimulationResults > PathAnalysis[modelId="'+modelId+'"] > Traces > Trace[id="' + traceId + '"]');
    if (traceNodeList.length != 1) {
        alert("Error retriving the Trace with id: " + traceId);
        return;
    }
    traceNode = traceNodeList[0];

    $("#name_traceProb_lbl").text(traceId);
    $("#prob_traceProb_lbl").text(traceNode.getAttribute("traceProbability") + '%');
    $("#execTime_traceProb_lbl").text(traceNode.getAttribute("executionTime"));
    $("#costs_traceProb_lbl").text(traceNode.getAttribute("costs"));
    $("#path_traceProb_lbl").text(traceNode.getAttribute("pathId"));
    $("#twt_traceProb_lbl").text(traceNodeList.find("WaitingTimes")[0].getAttribute("total"));
    $("#mwt_traceProb_lbl").text(traceNodeList.find("WaitingTimes")[0].getAttribute("totalOnMessages"));
    $("#sdtwt_traceProb_lbl").text(traceNodeList.find("WaitingTimes")[0].getAttribute("standardDeviation"));
    $("#sdmwt_traceProb_lbl").text(traceNodeList.find("WaitingTimes")[0].getAttribute("standardDeviationOnMessages"));
}



var chartTraceProbabilities = null;
function generateTraceProbabilitiesPie() {

    if (chartTraceProbabilities != null)
        chartTraceProbabilities.destroy();

    $('#traceListSelect').empty();

    var chartTraceProbabilitiesData = [];
    var chartTraceProbabilitiesUsedColorList = [];
    var traceList = xmlData.find('SimulationResults > PathAnalysis[modelId="'+modelId+'"] > Traces > Trace');

    for (var i = 0; i < traceList.length; i++) {
        var color = randomColorNotIn(chartTraceProbabilitiesUsedColorList);
        chartTraceProbabilitiesUsedColorList.push(color);

        chartTraceProbabilitiesData.push({
            value : traceList[i].getAttribute('traceProbability'),
            label : traceList[i].getAttribute('id'),
            color : color,
            highlight : '#E2E2E2'
        });

        $('#traceListSelect').append($('<option>', {
            value : traceList[i].getAttribute('id'),
            text : traceList[i].getAttribute('id')
        }));
    }

    chartTraceProbabilities = new Chart($("#canvasTraceProbabilities").get(0).getContext("2d")).Pie(chartTraceProbabilitiesData, {});

    onTraceSelectChange();
}

function showTrace() {
    var traceName = $('#traceListSelect').find(":selected").val();
    var jsonTraceInfo = generateJsonTrace(traceName);
    if(msgSourceWindow == null) {
        alert("Trace Elements:\n"+JSON.stringify(jsonTraceInfo, null, 2));
    } else {
        msgSourceWindow.postMessage(jsonTraceInfo, "*");
    }
}
function generateJsonTrace(traceId) {
    var objList = [];
    var xmlObjList = xmlData.find('SimulationResults > PathAnalysis[modelId="'+modelId+'"] > Traces > Trace[id="' + traceId + '"] > Steps > Object').each(function(){
        var objId = $(this).text();
        objList.push([objId]);
    });

    return {
        command: "show_trace",
        modelId: modelId,
        objList: objList
    };
}








var chartPathsExecTime = null;
function generatePathsExecTimeInstagram() {
    if (chartPathsExecTime != null)
        chartPathsExecTime.destroy();

    var chartPathsExecTimeData = {
        labels : [],
        datasets : [ {
            label : "Path / Execution Times (h)",
            fillColor : "#CCCCCC",
            strokeColor : "#CCCCCC",
            highlightFill : "#E2E2E2",
            highlightStroke : "#E2E2E2",
            data : []
        } ]
    };

    var traceList = xmlData.find('SimulationResults > PathAnalysis[modelId="'+modelId+'"] > Traces > Trace');

    for (var i = 0; i < traceList.length; i++) {
        var pathId = traceList[i].getAttribute('pathId');
        var execTime = traceList[i].getAttribute('executionTime');

        if ($.inArray(pathId, chartPathsExecTimeData.labels) == -1) {
            chartPathsExecTimeData.labels.push(pathId);
            chartPathsExecTimeData.datasets[0].data.push(adoxxTimeStringToHours(execTime));
        }
    }

    chartPathsExecTime = new Chart($("#canvasPathExecTime").get(0).getContext("2d")).Bar(chartPathsExecTimeData, {});
}

var lastPathExecTimeLabel = null;
function onOverPathExecTime(evt) {
    var activePoints = chartPathsExecTime.getBarsAtEvent(evt);
    if (activePoints.length == 0)
        return;

    var pathName = activePoints[0].label;

    if (lastPathExecTimeLabel != null && pathName == lastPathExecTimeLabel)
        return;
    lastPathExecTimeLabel = pathName;

    // the following code is executed only on selection change
    $('#pathListSelect').val(pathName);
    loadPathInfos(pathName);
};








var chartPathsCosts = null;
function generatePathsCostsInstagram() {
    if (chartPathsCosts != null)
        chartPathsCosts.destroy();

    var chartPathsCostsData = {
        labels : [],
        datasets : [ {
            label : "Path / Costs",
            fillColor : "#CCCCCC",
            strokeColor : "#CCCCCC",
            highlightFill : "#E2E2E2",
            highlightStroke : "#E2E2E2",
            data : []
        } ]
    };

    var traceList = xmlData.find('SimulationResults > PathAnalysis[modelId="'+modelId+'"] > Traces > Trace');

    for (var i = 0; i < traceList.length; i++) {
        var pathId = traceList[i].getAttribute('pathId');
        var costs = traceList[i].getAttribute('costs');

        if ($.inArray(pathId, chartPathsCostsData.labels) == -1) {
            chartPathsCostsData.labels.push(pathId);
            chartPathsCostsData.datasets[0].data.push(costs);
        }
    }

    chartPathsCosts = new Chart($("#canvasPathCosts").get(0).getContext("2d")).Bar(chartPathsCostsData, {});
}

var lastPathCostsLabel = null;
function onOverPathCosts(evt) {
    var activePoints = chartPathsCosts.getBarsAtEvent(evt);
    if (activePoints.length == 0)
        return;

    var pathName = activePoints[0].label;

    if (lastPathCostsLabel != null && pathName == lastPathCostsLabel)
        return;
    lastPathCostsLabel = pathName;

    // the following code is executed only on selection change
    $('#pathListSelect').val(pathName);
    loadPathInfos(pathName);
};







function randomColorNotIn(avoidList) {
    var color = randomColor();
    while ($.inArray(color, avoidList) != -1) {
        color = randomColor();
    }
    return color;
}

function randomColor() {
    return '#' + (0x1000000 + (Math.random()) * 0xffffff).toString(16).substr(1, 6);
}

function adoxxTimeStringToHours(adoxxTime) {
    // YY:DDD:HH:MM:SS
    // 0 1 2 3 4
    var data = adoxxTime.split(":");
    var hours = 0;
    hours += parseInt(data[4]) / 3600;
    hours += parseInt(data[3]) / 60;
    hours += parseInt(data[2]);
    hours += parseInt(data[1]) * 24;
    hours += parseInt(data[0]) * 8760;
    return hours;
}

var formatXml = this.formatXml = function(xml) {
    var reg = /(>)(<)(\/*)/g;
    var wsexp = / *(.*) +\n/g;
    var contexp = /(<.+>)(.+\n)/g;
    xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2');
    var pad = 0;
    var formatted = '';
    var lines = xml.split('\n');
    var indent = 0;
    var lastType = 'other';
    var transitions = {
        'single->single' : 0,
        'single->closing' : -1,
        'single->opening' : 0,
        'single->other' : 0,
        'closing->single' : 0,
        'closing->closing' : -1,
        'closing->opening' : 0,
        'closing->other' : 0,
        'opening->single' : 1,
        'opening->closing' : 0,
        'opening->opening' : 1,
        'opening->other' : 1,
        'other->single' : 0,
        'other->closing' : -1,
        'other->opening' : 0,
        'other->other' : 0
    };
    for (var i = 0; i < lines.length; i++) {
        var ln = lines[i];
        var single = Boolean(ln.match(/<.+\/>/));
        var closing = Boolean(ln.match(/<\/.+>/));
        var opening = Boolean(ln.match(/<[^!].*>/));
        var type = single ? 'single' : closing ? 'closing' : opening ? 'opening' : 'other';
        var fromTo = lastType + '->' + type;
        lastType = type;
        var padding = '';
        indent += transitions[fromTo];
        for (var j = 0; j < indent; j++) {
            padding += '    ';
        }
        formatted += padding + ln + '\n';
    }
    return formatted;
};

function getURLParameter(sParam) {
    var sPageURL = window.location.search.substring(1);
    var sURLVariables = sPageURL.split('&');
    for (var i = 0; i < sURLVariables.length; i++) {
        var sParameterName = sURLVariables[i].split('=');
        if (sParameterName[0] == sParam)
            return sParameterName[1];
    }
    return null;
}

function getHostname() {
    if (window.location.hostname == '')
        return '127.0.0.1:8080';
    return window.location.hostname + ':' + window.location.port;
}

function getProtocol() {
    if (window.location.protocol == '')
        return 'http:';
    return window.location.protocol;
}

function readSingleFile(e) {
    var file = e.target.files[0];
    if (!file) {
        return;
    }
    $('#labelSpan').text(file.name);
    var reader = new FileReader();
    reader.onload = function(e) {
        fileContent = e.target.result;
        // sessionStorage.setItem('adoxxSimModelContent', e.target.result);
    };
    // reader.readAsArrayBuffer(file);
    reader.readAsText(file);
}

function simulate() {

    var serviceEndpoint = getProtocol() + '//' + getHostname() + '/simulation';
    var host = getURLParameter("host");
    if (host != null)
        serviceEndpoint = host + '/simulation';

    if (fileContent == null)
        return;
    
    $('#inputModelTxt').html(fileContent);

    $.ajax({
        url : serviceEndpoint + '/rest/simulator/pathanalysis?numExecutions=' + escape($('#numExecutions').val()) + '&fullResults=' + $('#fullResultsChk').is(':checked'),
        type : 'POST',
        data : fileContent,
        dataType : 'text',
        contentType : 'application/xml',
        processData : false,
        async : true,
        success : function(data, status) {

            if(data.startsWith('<ERROR>')){
                alert(data);
                return;
            }
            
            $('#graphResults').show();

            $('#simulationResultsTxt').html(formatXml(data));

            xmlData = $(jQuery.parseXML(data));
            
            loadModelSelect();
            loadCharts();
        },
        error : function(request, status, error) {
            alert('Error: ' + status + ' ' + error);
        }
    });
    
    generatePNML();
}

function generatePNML() {

    var serviceEndpoint = getProtocol() + '//' + getHostname() + '/simulation';
    var host = getURLParameter("host");
    if (host != null)
        serviceEndpoint = host + '/simulation';

    if (fileContent == null)
        return;

    $.ajax({
        url : serviceEndpoint + '/rest/utils/showpetrinet',
        type : 'POST',
        data : fileContent,
        dataType : 'text',
        contentType : 'application/xml',
        processData : false,
        async : true,
        success : function(data, status) {

            if(data.startsWith('<ERROR>')){
                alert(data);
                return;
            }
            
            $('#petrinetTxt').html(data);
        },
        error : function(request, status, error) {
            alert('Error: ' + status + ' ' + error);
        }
    });
}

function loadCharts(){
    
    loadGeneralResults();
    loadActivitiesSelect();
    generatePathProbabilitiesPie();
    generateTraceProbabilitiesPie();
    generatePathsExecTimeInstagram();
    generatePathsCostsInstagram();
}

function onMessageReceived(event) {
    var origin = event.origin || event.originalEvent.origin;
    fileContent = event.data;
    msgSourceWindow = event.source;
}

//window.addEventListener("message", onMessageReceived, false);
window.onmessage = onMessageReceived;

function skipModelSelection() {
    return getURLParameter("skipModelSelection") == 'true';
}

$(document).ready(function() {

    if (!skipModelSelection()) {
        if (window.File && window.FileReader && window.FileList && window.Blob) {
            document.getElementById('file-input').addEventListener('change', readSingleFile, false);
        } else {
            alert('The File APIs are not fully supported in this browser.');
        }
    } else {
        $('#inputDiv').hide();
    }

    $('#graphResults').hide();

    document.getElementById('model_generalRes_select').addEventListener('change', onModelSelectChange);
    
    document.getElementById('activityRes_select').addEventListener('change', onActivitiesSelectChange);
    
    document.getElementById('canvasPathProbabilities').addEventListener('mousemove', onOverPathProbabilities);
    document.getElementById('pathListSelect').addEventListener('change', onPathSelectChange);

    document.getElementById('canvasTraceProbabilities').addEventListener('mousemove', onOverTraceProbabilities);
    document.getElementById('traceListSelect').addEventListener('change', onTraceSelectChange);

    document.getElementById('canvasPathExecTime').addEventListener('mousemove', onOverPathExecTime);
    document.getElementById('canvasPathCosts').addEventListener('mousemove', onOverPathCosts);

    document.getElementById('totDeadP_generalRes_select').addEventListener('change', onDeadPathSelectChange);
    document.getElementById('maxCostTrace_generalRes_lbl').addEventListener('click', changeTrace);
    document.getElementById('minCostTrace_generalRes_lbl').addEventListener('click', changeTrace);
    document.getElementById('maxExecTimeTrace_generalRes_lbl').addEventListener('click', changeTrace);
    document.getElementById('minExecTimeTrace_generalRes_lbl').addEventListener('click', changeTrace);
    document.getElementById('maxWaitTimeTrace_generalRes_lbl').addEventListener('click', changeTrace);
    document.getElementById('maxMsgWaitTimeTrace_generalRes_lbl').addEventListener('click', changeTrace);
    document.getElementById('minWaitTimeTrace_generalRes_lbl').addEventListener('click', changeTrace);
    document.getElementById('minMsgWaitTimeTrace_generalRes_lbl').addEventListener('click', changeTrace);

    document.getElementById('path_traceProb_lbl').addEventListener('click', changePath);

    document.getElementById('minwtt_pathProb_lbl').addEventListener('click', changeTrace);
    document.getElementById('minmsgwtt_pathProb_lbl').addEventListener('click', changeTrace);
    
    document.getElementById('show_trace_lbl').addEventListener('click', showTrace);
    document.getElementById('show_path_lbl').addEventListener('click', showPath);
    
    document.getElementById('show_object_lbl').addEventListener('click', showActivity);
});